/*
 
	JTStrengthTester.m
	PasswordStrength

	Created by Jim Turner on 1/11/10 for http://nukethemfromorbit.com/

	Ported from QualityEstimation.cs from the http://keepass.info/ project
	Copyright (C) 2003-2009 Dominik Reichl <dominik.reichl@t-online.de>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


#import "JTStrengthTester.h"
#include <math.h>

@implementation JTStrengthTester

+(NSUInteger) checkStrengthOfPassword:(NSString *)password
{
	BOOL chLower = NO;
	BOOL chUpper = NO;
	BOOL chNumber = NO;
	BOOL chSimpleSpecial = NO;
	BOOL chExtSpecial = NO;
	BOOL chHigh = NO;
	BOOL chEscape = NO;
	double effectiveLength = 0.0;
	NSUInteger charSpace = 0;
	NSCountedSet *differences = [[[NSCountedSet alloc] initWithCapacity:[password length]] autorelease];
	NSCountedSet *charCounts = [[[NSCountedSet alloc] initWithCapacity:[password length]] autorelease];
	
	for( NSInteger x=0; x<[password length]; x++ )
	{
		unichar tch = [password characterAtIndex:x];

		if( tch < ' ' ) chEscape = YES;
		if( (tch >= 'A') && (tch <= 'Z') ) chUpper = YES;
		if( (tch >= 'a') && (tch <= 'z') ) chLower = YES;
		if( (tch >= '0') && (tch <= '9') ) chNumber = YES;
		if( (tch >= ' ') && (tch <= '/') ) chSimpleSpecial = YES;
		if( (tch >= ':') && (tch <= '@') ) chExtSpecial = YES;
		if( (tch >= '[') && (tch <= '`') ) chExtSpecial = YES;
		if( (tch >= '{') && (tch <= '~') ) chExtSpecial = YES;
		if( tch > '~' ) chHigh = YES;

		double diffFactor = 1.0;
		if( x >= 1 )
		{
			NSInteger diff = (NSInteger)tch - (NSInteger)[password characterAtIndex:x-1];
#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_4
	#if __LP64__ || NS_BUILD_32_LIKE_64
			NSNumber *diffObj = [NSNumber numberWithLong:(long)diff];
	#else
			NSNumber *diffObj = [NSNumber numberWithInt:(int)diff];
	#endif
#else
			NSNumber *diffObj = [NSNumber numberWithInteger:diff];
#endif			
			if( ![differences countForObject:diffObj] )
				[differences addObject:diffObj];
			else
			{
				[differences addObject:diffObj];
				diffFactor /= (double)[differences countForObject:diffObj];
			}
		}
		
		NSString *charObj = [NSString stringWithCharacters:&tch length:1];
		if( ![charCounts countForObject:charObj] )
		{
			[charCounts addObject:charObj];
			effectiveLength += diffFactor;
		}
		else
		{
			[charCounts addObject:charObj];
			effectiveLength += diffFactor * (1.0 / (double)[charCounts countForObject:charObj]);
		}
	}

	if( chEscape ) charSpace += Escape;
	if( chUpper ) charSpace += Alpha;
	if( chLower ) charSpace += Alpha;
	if( chNumber ) charSpace += Number;
	if( chSimpleSpecial ) charSpace += SimpleSpecial;
	if( chExtSpecial ) charSpace += ExtendedSpecial;
	if( chHigh ) charSpace += High;
	
	if( charSpace == 0 )
		return( 0 );
		
	double bitsPerChar = log( charSpace ) / log( 2.0 );
	NSUInteger result = (NSUInteger)ceil( bitsPerChar * effectiveLength );
	
	return( result );
}

@end
